package client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import chat.ChatProtocol;
import chat.Message;

/**
 * Chat Client class for ACE4.
 * 
 * @author derykegan
 * 
 */
public class ChatClient extends Thread {

	ChatProtocol received, lastReceived;
	Socket sock;
	String host; 		//hostname to connect to
	int socketNumber; 	//socket number on host

	InputStream in = null;
	ObjectOutputStream oos = null;
	boolean debug = false;

	String username; // the user's name
	ChatProtocol theMessage; // packaged message
	
	String userInput; // user input string
	boolean newInput = false;

	Calendar calendar = new GregorianCalendar();
	SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");

	ObjectInputStream ois;

	/**
	 * Main chat client thread.
	 * @param host			hostname to connect to	
	 * @param socketNumber	socket number on host	
	 * @param debug			true for extra debug text	
	 * @param name 			desired username
	 * @throws IOException
	 */
	public ChatClient(String host, int socketNumber, boolean debug, String name) throws IOException {
		this.host = host;
		this.socketNumber = socketNumber;
		this.debug = debug;
		username = name;
	}
	
	
	/**
	 * Container class for each client thread. Keeps track
	 * if we've read in a message and what it is.
	 * @author derykegan
	 *
	 */
	class ReadIn{
		
		private boolean changed = false;
		private ChatProtocol newMessage;
		
		public ReadIn(){
			
		}
		
		synchronized public void addMessage(ChatProtocol message){
			this.newMessage = message;
			changed = true;
		}
		
		synchronized public boolean getChanged(){
			return changed;
		}
		
		synchronized public ChatProtocol getMessage(){
			changed = false;
			return newMessage;
		}
		
	}
	

	/**
	 * Sends message to server.
	 * @param input
	 */
	private void submitMessage(String input) {
			if (debug)
				System.out.println("CLIENT - NEW MESSAGE INPUT");

			/* update to current system time */
			calendar = GregorianCalendar.getInstance();

			Message newMessage = new Message(format.format(calendar.getTime()),
					username, input);
			/* write message to socket */
			try {
				oos.writeObject(new ChatProtocol(
						ChatProtocol.MESSAGE_TO_SERVER, newMessage));
				oos.flush();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			if (debug)
				System.out.println("CLIENT - MESSAGE WRITTEN");
		
	}

	@Override
	public void run() {
		try {
			/* open socket */
			sock = new Socket(host, socketNumber);
			if (debug)
				System.out.println("Socket opened.");

			/* set up input and output objects */

			oos = new ObjectOutputStream(sock.getOutputStream());

			in = sock.getInputStream();
			ois = new ObjectInputStream(in);

			(new Thread(this)).start();

			if (debug)
				System.out.println("waiting for welcome");

			ReadIn read = new ReadIn();
			ChatThreadListen listenThread = new ChatThreadListen(in, read);
			listenThread.start();
			
			/* --- main chat loop --- */
			boolean executing = true;

			while (executing) {
				
				/* if user has input text */
				if(newInput){
					newInput = false;
					submitMessage(userInput);
				}
				
				ChatProtocol messageRead = null;

				/* check if message received from server */
				if (read.getChanged()){
					messageRead = read.getMessage();
					
					/* check if we have received a message from server */
					if (messageRead != null) {

						if (debug)
							System.out
									.println("CLIENT - MESSAGE RECEIVED FROM SERVER");

						/* check type of message ... */

						/* if server has shut down */
						if (messageRead.getState() == ChatProtocol.SERVER_DISCONNECT) {
							System.out
									.println("Server disconnected, shutting down.");
							executing = false;
							break;
						}

						/* if server has sent a status message */
						if (messageRead.getState() == ChatProtocol.SERVER_STATUS_MESSAGE) {
							System.out.printf("SERVER MESSAGE: ");
							System.out.println(messageRead.getMessage().getTime()
									+ " "
									+ messageRead.getMessage().getMessageText());
						}

						/* if we have a new chat message */
						if (messageRead.getState() == ChatProtocol.MESSAGE_FROM_SERVER) {
							Message m = messageRead.getMessage();
							System.out.printf(m.getTime() + " " + m.getUsername()
									+ ": ");
							System.out.println(m.getMessageText());
						}

					}
					
				}

				/* give other threads a chance to execute */
				Thread.sleep(200);
			}

			/* no longer executing */

		} catch (Exception e) {
			e.printStackTrace();
		}

		finally {
			/* write message to socket */
			try {
				oos.writeObject(new ChatProtocol(
						ChatProtocol.CLIENT_DISCONNECT, null));
				oos.flush();
				in.close();
				sock.close();
				System.out.println("\nClient shutdown.");
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * Set user input
	 * @param input
	 */
	public void setInput(String input){
		userInput = input;
		newInput = true;
	}
}
